Design by Contract: Perl6/VB Preconditions and Postcondition

Mark Leighton Fisher on 2006-06-30T16:30:04

Like I've said, Perl5 lvalue subs by themselves are not useful for Design by Contract-style data validation preconditions and postconditions, as you cannot examine the data on input or output (but check out the comments on that post). No such limitation exists with Perl6 rw subs and Visual Basic Properties, so let's see some examples of data validation preconditions and postconditions.

This Perl6 example should work in the current Pugs (tested on the Win32 Pugs of June 6, 2006, 04:35 EST). A variable that can only have the values of:

  • The empty string,""; or
  • A specific URL

can be implemented in Perl6 today with an rw sub as:

my $url_value = "";
sub specific_url is rw {
     if ($url_value ne "http://example.com/stories") {
          $url_value = "";
     } else {
          $url_value = "http://example.com/stories";
     }
     return $url_value;
}

The sequence:

specific_url() = "http://example.com/stories";
say "specific_url = ", specific_url(), "\n";
specific_url() = "http://example.com/news";
say "specific_url = ", specific_url(), "\n";

yields this output:

specific_url = http://example.com/stories
specific_url =

As specified above, specific_url() can only be assigned a value of "http://example.com/stories". Any other attempt at assignment causes specific_url() to take on a value of "".

Although VB Properties were originally designed for exposing the adjustable parameters of Windows controls (comboboxes, timers, etc.), they also provide a dandy way to give your VB variables their preconditions and postconditions. A VB class property for U.S. Social Security numbers would look like this (along with a 'notSS' property for comparison purposes):

Public Property Let SocialSecurity(newSocialSecurity As String)
    If Not newSocialSecurity Like "###-##-####" Then
        mSocialSecurity = ""
    Else
        mSocialSecurity = newSocialSecurity
    End If
End Property
Public Property Get SocialSecurity() As String
    SocialSecurity = mSocialSecurity
End Property

Public Property Let notSS(newNotSS As String)
    mNotSS = newNotSS
End Property
Public Property Get notSS() As String
    notSS = mNotSS
End Property

SocialSecurity can only be assigned a validly-formatted U.S. Social Security number, yet code that uses the SocialSecurity Property looks just like code that uses a VB String for a Social Security number:

    ss1.notSS = "300-42-980A"
    ss1.SocialSecurity = "300-42-980A"
    ss2.SocialSecurity = "300-42-9805"

    Debug.Print "notSS = '" & ss1.notSS & "'"
    Debug.Print "ss1 = '" & ss1.SocialSecurity & "'"
    Debug.Print "ss2 = '" & ss2.SocialSecurity & "'"

yields this output:

    notSS = '300-42-980A'
    ss1 = ''
    ss2 = '300-42-9805'

As you can see, the SocialSecurity property only accepts a validly-formatted U.S. Social Security number, but the plain String-valued Property accepts any old String value.

There's much more to Design by Contract than preconditions and postconditions, of course, but this brief essay should give you a leg up on this important technique for easing the pain of data validation.